package enemies 
{
	import collisions.Body;
	import collisions.LinkedList;
	import collisions.QuadTree;
	import entities.Entity;
	import events.Alert;
	import events.EventBus;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	import player.Player;
	import renderers.Renderer;
	
	/**
	 * ...
	 * @author Gareth Williams
	 * todo: extract state change mechanism funcitonality
	 * todo: typed states
	 * todo: implement alerts on player sighting
	 * todo: abstract to an interface so we can use strategies instead of states for 
	 * 			state machine implementation - much neater.
	 * todo: narrowphase physics for increased granularity
	 */
	public class Enemy extends Entity
	{
		//state machine properties
		private var state:Strategy = null;
		
		public var fireProbability:Number = 0.1;
		public var weaponStrength:int = 1; //different enemies will have different weapons
		
		public function Enemy(x:Number = 0, y:Number = 0, radius:Number = 10) 
		{
			speed = 1;
			super(x, y, radius);
			
			//listen for alert events from other enemies who have spotted player
			//EventBus.addEventListener(Alert.ENTITY_SIGHTED, onPlayerSighted); 
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.onTimeOut);
		}
		override public function destructor():void 
		{
			super.destructor();
		}
		public function receiveDamage(amount:int):void
		{
			this.percentHealth -= amount;
			//this.graphic.doHitAnimation();
			//this.graphic.doHealthAnimation(percentHealth);
			if (true == checkWhetherDead())
			{
				this.isAlive = false;
				//this.graphic.doDeathAnimation();
			}
		}
		override public function update():void //Entity
		{
			if (isAlive == false) return;
			
			//strategy
			var strategyCompleted:Boolean = state.perform(this);
			if (strategyCompleted)
			{
				//select a new strategy
			}
			//viewcone
			this.viewCone.angleInRadians = this.rotation;
		}
		//collision detection (broadphase)
		override public function processProximityTo(collider:Body):void //Body
		{	
			//narrowphase comes from pixel-perfect collision detection algorithm
			//http://anotherearlymorning.com/files/PixelPerfectCollisionDetection.as
			//although the originator of this concept was Andre Michelle
			//if pixel precise (fourth option) is false (default) we just use bounding boxes and save a lot of processing...
			var narrowCollision:Boolean = PixelPerfectCollisionDetection.isColliding(this.graphic, Entity(collider).graphic, Renderer.rootDisplayObject);
			if (narrowCollision == false) return;
			
			//implement view cone
			var delta:Point = Point(collider).subtract(this);
			var angleToChild:Number = Math.atan2(delta.y, delta.x); //+ Constants.HALF_PI;
			
			//unit vectors
			var aX:Number = Math.cos(viewCone.angleInRadians);
			var aY:Number = Math.sin(viewCone.angleInRadians);
			var bX:Number = Math.cos(angleToChild);
			var bY:Number = Math.sin(angleToChild);
			
			var dotProduct:Number = (aX * bX) + (aY * bY);
			var aperture:Number = Math.cos(this.viewCone.fovInRadians * 0.5);
				
			//test orthogonal
			var isVisible:Boolean = Boolean(dotProduct >= aperture);
			
			if (isVisible)
			{
				//other types of entities may exist later like crates...
				if (collider is Player)
				{
					//raise the alarm
					//if (state !== SEEK) EventBus.dispatchEvent(new Alert(Alert.ENTITY_SIGHTED, this));
					
					//attack
					//var isFiring:Boolean = Math.random() < this.fireProbability;
					//if (isFiring) Player(collider).receiveDamage(weaponStrength);
				}
			}
		}
		//handlers
		/*
		private function onPlayerSighted(alert:Alert):void 
		{
			if (alert.dispatcher === this) return;
			
			//move alerter
			this.target = alert.dispatcher as Point;
			this.state = Enemy.WANDER;
		}
		*/
		//helpers
		private function checkWhetherDead():Boolean
		{
			return percentHealth <= 0;
		}
	}
}